<html>
    <head>
        <title>处理多实现</title>
    </head>
    <body>
        <script>
            /*
                            十四、处理多实现

                                    你可以注册统一服务接口的多个实现。假设你有一个 IExternalLogger 接口，具有两个实现：
                                                
                                                // 声明 IExterbalLogger 接口
                                                public interface IExternalLogger
                                                {
                                                    Task LogAsync(string logText);
                                                }

                                                // 第一个实现类
                                                public class ElasticsearchExternalLogger : IExternalLogger
                                                {
                                                    public async Task LogAsync(string logText)
                                                    {
                                                        //TODO...
                                                    }
                                                }

                                                // 第二个实现类
                                                public class AzureExternalLogger : IExternalLogger
                                                {
                                                    public Task LogAsync(string logText)
                                                    {
                                                        throw new System.NotImplementedException();
                                                    }
                                                }

                                    在这个例子中，我们还没有讲任何实现类注册到依赖注入系统。
                                    一次，如果我们尝试注入 IExternalLogger接口，我们会得到一个错误，表明没有找到实现。

                                    如果我们为IExternalLogger接口注册 ElasticsearchExternalLogger 和 AzureExternalLogger，然后尝试注入 IExternalLogger，
                                    则将使用最后注册的实现。

                                    注入IExternalLogger接口的示例服务：
                                            public class MyService : ITransientDependency
                                            {
                                                private readonly IExternalLogger _externalLogger;

                                                public MyService(IExternalLogger externalLogger)
                                                {
                                                    _externalLogger = externalLogger;
                                                }

                                                public async Task DemoAsync()
                                                {
                                                    await _externalLogger.LogAsync("Example log message...");
                                                }
                                            }  
                                    在这里，如前所述，我们得到最后一个注册的实现。但是，如何确定最后一个注册的实现？  
                                    如果我们实现了其中一个依赖接口（例如ITransientDependency），那么注册顺序将是不确定的（它可能取决于类的命名空间）。
                                    最后注册的实现可能与你的预期的不同。因此，不建议使用依赖接口来注册多个实现。  
                                    
                                    
                                    你可以在模块的 ConfigureServices() 方法中注册你的服务：

                                            public override void ConfigureServices(ServiceConfigurationContext context)
                                            {
                                                context.Services.AddTransient<IExternalLogger, ElasticsearchExternalLogger>();
                                                context.Services.AddTransient<IExternalLogger, AzureExternalLogger>();
                                            }

                                    在这种情况下，当你注入IExternalLogger接口时，你会得到一个AzureExternalLogger实例，因为最后注册的实现是AzureExternalLogger类。

                                    当你有一个借口的多个实现时，你可能希望使用所有这些实现。
                                    假设你要将日志写入所有外部记录器。我们可以将MyService实现更改为以下内容：

                                            public class MyService : ITransientDependency
                                            {
                                                // 注入 IEnumerable<IExternalLogger> 而不是 IExternalLogger。
                                                private readonly IEnumerable<IExternalLogger> _externalLoggers;

                                                public MyService(IEnumerable<IExternalLogger> externalLoggers)
                                                {
                                                    _externalLoggers = externalLoggers;
                                                }

                                                public async Task DemoAsync()
                                                {
                                                    // 遍历所有外部记录器并写入日志。
                                                    foreach (var externalLogger in _externalLoggers)
                                                    {
                                                        await externalLogger.LogAsync("Example log message...");
                                                    }
                                                }
                                            }

                                    在这个例子中，我们注入了 "IEnumerable<IExternalLogger>"  而不是IExternalLogger，
                                    所以，我们有了一个IExternalLogger 接口的所有已注册实现的集合。
                                    然后我们使用foreach循环将相同的日志文本写入所有IExternalLogger实现。

                                    如果你是用IServiceProvider来解析依赖关系，则使用其 GetServices 方法来获取服务的实现集合：

                                        IEnumerable<IExternalLogger> services = _serviceProvider.GetServices<IExterbalLogger>();
                    */
        </script>
    </body>
</html>